package com.person.commons.utils;

import java.io.Serializable;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.person.commons.exception.InfrastructureException;
import com.person.sys.model.SysLog;

public class DAOImpl extends HibernateDaoSupport implements DAO {

	private static final ThreadLocal counter = new ThreadLocal();

	/**
	 * 新增一个BEO对象，在数据库插入一条记录
	 * 
	 * @param beo
	 *            要新增的BEO对象
	 * @return 主键对象
	 */
	public Serializable save(Object beo) {
		Serializable pk = getHibernateTemplate().save(beo);
		autoFlush(1);
		return pk;
	}

	/**
	 * 删除一个BEO对象，在数据库删除一条记录
	 * 
	 * @param beo
	 *            要删除的BEO对象
	 */
	public void delete(Object beo) {
		getHibernateTemplate().delete(beo);
		autoFlush(1);
	}

	/**
	 * 根据主键对象删除一个BEO，在数据库删除一条记录
	 * 
	 * @param beoCls
	 *            要删除的BEO所属类
	 * @param pk
	 *            BEO主键对象
	 */
	public void delete(Class beoCls, Serializable pk) {
		Object beo = find(beoCls, pk);
		if (beo != null) {
			delete(beo);
			autoFlush(1);
		}
	}

	/**
	 * 根据HQL语句批量删除或更新BEO，在数据库批量删除或更新记录，如： <br>
	 * dao.updateBulk("delete from Ab01 ab01");<br>
	 * dao.updateBulk("update Ab01 ab01 set ab01.aab004='test' where
	 * ab01.CompositeId.aab034='1000000001'");
	 * 
	 * @param hql
	 *            要批量删除或更新BEO的HQL语句
	 * @return 删除或更新的记录数
	 */
	public int updateBulk(String hql) {
		int c = getHibernateTemplate().bulkUpdate(hql);
		autoFlush(c);
		return c;
	}

	/**
	 * 根据HQL语句批量删除或更新BEO，在数据库批量删除或更新记录，如： <br>
	 * dao.updateBulk("delete from Ab01 ab01 where ab01.CompositeId.aab034=?",
	 * "1000000001"); <br>
	 * dao.updateBulk("update Ab01 ab01 set ab01.aab004=? where
	 * ab01.CompositeId.aab034='1000000001'", "test");
	 * 
	 * @param hql
	 *            要批量删除或更新BEO的HQL语句
	 * @param value
	 *            HQL语句中的参数值
	 * @return 删除或更新的记录数
	 */
	public int updateBulk(String hql, Object value) {
		int c = getHibernateTemplate().bulkUpdate(hql, value);
		autoFlush(c);
		return c;
	}

	/**
	 * 根据HQL语句批量删除或更新BEO，在数据库批量删除或更新记录，如： <br>
	 * dao.updateBulk("delete from Ab01 ab01 where ab01.CompositeId.aab034=? and
	 * ab01.aab004=?", new Object[]{"1000000001", "test"}); <br>
	 * dao.updateBulk("update Ab01 ab01 set ab01.aab004=? where
	 * ab01.CompositeId.aab034=?", new Object[]{"test", "1000000001"});
	 * 
	 * @param hql
	 *            要批量删除或更新BEO的HQL语句
	 * @param value
	 *            HQL语句中的参数值
	 * @return 删除或更新的记录数
	 */
	public int updateBulk(String hql, Object[] values) {
		int c = getHibernateTemplate().bulkUpdate(hql, values);
		autoFlush(c);
		return c;
	}

	/**
	 * 更新一个BEO对象，在数据库更新一条记录
	 * 
	 * @param beo
	 *            要更新的BEO对象
	 */
	public void update(Object beo) {
		getHibernateTemplate().update(beo);
		autoFlush(1);
	}

	/**
	 * 带锁查询
	 * 
	 * @param alias
	 *            HQL查询语句中需要所定的表别名 例如：'aa10' -> from Aa10 aa10 'ab01' ->from
	 *            Ab01 ab01
	 * @param hql
	 *            查询HQL语句
	 * @return
	 */
	public Object find(Class beoCls, Serializable pk) {
		return getHibernateTemplate().get(beoCls, pk);
	}

	/**
	 * 带锁查询
	 * 
	 * @param alias
	 *            HQL查询语句中需要所定的表别名 例如：'aa10' -> from Aa10 aa10 'ab01' ->from
	 *            Ab01 ab01
	 * @param hql
	 *            查询HQL语句
	 * @param values
	 *            HQL语句中的参数值
	 * @return
	 */
	public List find(String hql) {
		return getHibernateTemplate().find(hql);
	}

	/**
	 * 根据主键查询BEO对象，从数据库查询一条记录 未查询到则返回null
	 * 
	 * @param beoCls
	 *            BEO所属类
	 * @param pk
	 *            BEO主键对象
	 * @return 查询出的BEO对象
	 */
	public List findWithLock(String alias, final String hql) {
		return findWithLock(alias, hql, null);
	}

	/**
	 * 根据传入的HQL查询
	 * 
	 * @param hql
	 *            查询HQL语句
	 * @return 查询结果列表
	 */
	public List findWithLock(final String alias, final String hql,
			final Object[] values) {
		return (List) getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException {
				Query queryObject = session.createQuery(hql);
				if (values != null) {
					for (int i = 0; i < values.length; i++) {
						queryObject.setParameter(i, values[i]);
					}
				}
				queryObject.setLockMode(alias, LockMode.UPGRADE);
				return queryObject.list();
			}
		}, true);
	}

	/**
	 * 根据传入的HQL查询
	 * 
	 * @param hql
	 *            查询HQL语句
	 * @param value
	 *            HQL查询语句中的参数值
	 * @return 查询结果列表
	 */
	public List find(String hql, Object value) {
		return getHibernateTemplate().find(hql, value);
	}

	/**
	 * 根据传入的HQL查询
	 * 
	 * @param hql
	 *            查询HQL语句
	 * @param values
	 *            HQL查询语句中的参数值
	 * @return 查询结果列表
	 */
	public List find(String hql, Object[] values) {
		return getHibernateTemplate().find(hql, values);
	}

	/**
	 * 锁定记录
	 * 
	 * @param entity
	 *            要锁定的记录对象
	 */
	public void lock(Object entity) {
		getHibernateTemplate().lock(entity, LockMode.UPGRADE);
	}

	/**
	 * 根据传入的HQL语句和翻页信息做查询
	 * 
	 * @param hql
	 *            查询HQL语句
	 * @param fpi
	 *            翻页信息对象
	 * @return 翻页信息对象
	 */
	public FlipPageInfo findWithPaging(final String hql, final FlipPageInfo fpi) {
		return findWithPaging(hql, fpi, null);
	}

	/**
	 * 根据传入的HQL语句和翻页信息做查询
	 * 
	 * @param hql
	 *            查询HQL语句
	 * @param fpi
	 *            翻页信息对象
	 * @param value
	 *            HQL查询语句中的参数值
	 * @return 翻页信息对象
	 */
	public FlipPageInfo findWithPaging(final String hql,
			final FlipPageInfo fpi, final Object value) {
		return findWithPaging(hql, fpi, new Object[] { value });
	}

	/**
	 * 根据传入的HQL语句和翻页信息做查询
	 * 
	 * @param hql查询HQL语句
	 * @param fpi
	 *            翻页信息对象
	 * @param value
	 *            HQL查询语句中的参数值
	 * @return 翻页信息对象
	 */
	public FlipPageInfo findWithPaging(final String hql,
			final FlipPageInfo fpi, final Object[] values) {
		return findWithPaging(hql, fpi, values, null);
	}

	/**
	 * 根据传入的HQL语句和翻页信息做查询
	 * 
	 * @param hql查询HQL语句
	 * @param fpi
	 *            翻页信息对象
	 * @param value
	 *            HQL查询语句中的参数值
	 * @param countString
	 *           用于代替count(*)中*的内容
	 * @return 翻页信息对象
	 */
	public FlipPageInfo findWithPaging(final String hql,
			final FlipPageInfo fpi, final Object[] values, String countString) {
		int idx = hql.indexOf("from");
		if (idx == -1)
			throw new InfrastructureException("Illegal hql that not contain 'from' keyword.");
		if (countString != null && !"".equals(countString.trim())) {
			List list = getHibernateTemplate().find(
					"select count(" + countString + ")" + hql.substring(idx),
					values);
			if (list.size() > 1) {
				fpi.setTotal(new Long(list.size()));
			} else {
				if (list.iterator().hasNext()) {
					fpi.setTotal((Long) list.iterator().next());
				} else {
					fpi.setTotal(new Long(0));
				}
			}
		} else {
			List list = getHibernateTemplate().find(
					"select count(*)" + hql.substring(idx), values);
			if (list.size() > 1) {
				fpi.setTotal(new Long(list.size()));
			} else {
				if (list.iterator().hasNext()) {
					fpi.setTotal(Long.valueOf(list.iterator().next().toString()));
				} else {
					fpi.setTotal(new Long(0));
				}
			}
		}
		if (fpi.getTotal().intValue() == 0)
			fpi.setPage(new Integer(0));
		else {
			if (fpi.getPage() == null || fpi.getPage().intValue() < 1)
				fpi.setPage(new Integer(1));
			else if (fpi.getPage().intValue() > fpi.getPages().intValue())
				fpi.setPage(fpi.getPages());
		}
		if (fpi.getTotal().intValue() > 0) {
			fpi.setData((List) getHibernateTemplate().execute(
					new HibernateCallback() {
						public Object doInHibernate(Session session)
								throws HibernateException {
							StringBuffer hqlBuffer = new StringBuffer();
							String originOrder = null;
							int orderByIdx = hql.indexOf("order by");
							if (orderByIdx != -1) {
								hqlBuffer.append(hql.substring(0, orderByIdx));
								originOrder = hql.substring(orderByIdx + 8);
							} else {
								hqlBuffer.append(hql);
							}

							String sortField = fpi.getSortField();
							String sortOrder = fpi.getSortOrder();
							if (sortField != null && !sortField.equals("")) {
								hqlBuffer.append(" order by ")
										.append(sortField);
								if (sortOrder != null && !sortOrder.equals(""))
									hqlBuffer.append(" ").append(sortOrder);
								if (originOrder != null)
									hqlBuffer.append(",").append(originOrder);
							} else if (originOrder != null) {
								hqlBuffer.append(" order by ").append(
										originOrder);
							}
							Query queryObject = session.createQuery(hqlBuffer
									.toString());
							if (values != null) {
								for (int i = 0; i < values.length; i++) {
									queryObject.setParameter(i, values[i]);
								}
							}
							if (fpi.getPage() != null
									&& fpi.getPage().intValue() > 0
									&& fpi.getSize() != null
									&& fpi.getSize().intValue() > 0) {
								queryObject.setFirstResult(fpi.getSize()
										.intValue()
										* (fpi.getPage().intValue() - 1));
								queryObject.setMaxResults(fpi.getSize()
										.intValue());
							}
							return queryObject.list();
						}
					}, true));
		} else {
			fpi.setData(new ArrayList());
		}

		return fpi;
	}

	private void autoFlush(final int c) {
		Integer count = (Integer) counter.get();
		if (count == null) {
			count = new Integer(0);
		}
		if (count.intValue() % 25 == 0) {
			getHibernateTemplate().flush();
			getHibernateTemplate().clear();
			count = new Integer(0);
		}
		counter.set(new Integer(count.intValue() + c));
	}

	// ���sql�Ͳ���ֱ��ȡ����
	public Object get(String hsql, Object[] params) {
		if (params == null) {
			return this.find(hsql).get(0);
		} else if (this.find(hsql, params).size() > 0) {
			return this.find(hsql, params).get(0);
		} else {
			return null;
		}

	}
	
	/**
	 * 该方法负责向sys_log表中增加一条日志记录
	 * 传递的SysLog对象中需要设置的参数有：userId,logIp,codeNo,logContent 
	 * @return 1 成功 0 失败
	 * @author wang zitao 
	 *
	 */
	public char createLog(SysLog sysLog){
		try{
		sysLog.setLogTime(new Date());
		String logId=(String)save(sysLog);
		return '1';
		}
		catch(InfrastructureException e)
		{
			return '0';
		}
	}

	@Override
	public long sumRecords(String sql) {
		List<Object> objList = getSession().createSQLQuery(sql).list();
		if(objList.size() > 0){
			try {
				return (Long) objList.get(0);
			}catch(HibernateException e){
//				e.printStackTrace();
			} catch (Exception e) {
//				e.printStackTrace();
			}
		}
		return 0;
	}

	@Override
	public int countRecords(String sql) {
		List<Object> objList = getSession().createSQLQuery(sql).list();
		if(objList.size() > 0){
			try {
				return (Integer) objList.get(0);
			} catch (Exception e) {
//				e.printStackTrace();
			}
		}
		return 0;
	}

	@Override
	public void delOrUpdate(String sql) {
		Connection con =getSession().connection();
		try {
			con.createStatement().execute(sql);
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}
